Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 18, 2025

Summary

What changed?

  • Improved the DurableTask source generator to use intelligent auto-detection of project type based on actual usage of Azure Functions trigger attributes
  • Added optional MSBuild property DurableTaskGeneratorProjectType for manual override when needed
  • Changed primary detection from assembly references to checking for OrchestrationTrigger, ActivityTrigger, and EntityTrigger attributes
  • Added comprehensive unit tests covering all configuration scenarios

Why is this change needed?

The generator was using assembly references to detect Azure Functions projects, which caused issues when projects had transitive dependencies on Functions packages but were actually building standalone Durable Task Worker applications. This prevented the AddAllGeneratedTasks method from being generated, breaking the standalone worker registration pattern.

Issues / work items

  • Resolves the issue where transitive dependencies on Azure Functions packages would force Functions code generation

Project checklist

  • Release notes are not required for the next release
  • Backport is not required
  • All required tests have been added/updated (unit tests, E2E tests)
  • Breaking change?

AI-assisted code disclosure (required)

Was an AI tool used? (select one)

  • Yes, an AI agent generated most of this PR

If AI was used:

  • Tool(s): GitHub Copilot Agent
  • AI-assisted areas/files:
    • src/Generators/DurableTaskSourceGenerator.cs - Added MSBuild property reading, implemented DetermineIsDurableFunctions method
    • src/Generators/README.md - Added documentation for auto-detection and configuration
    • test/Generators.Tests/ProjectTypeConfigurationTests.cs - Added 10 unit tests for configuration scenarios
    • test/Generators.Tests/Utils/TestHelpers.cs - Added overload for RunTestAsync to support projectType parameter
  • What you changed after AI output:
    • Iterated on detection logic based on reviewer feedback to use trigger attributes instead of just assembly references
    • Simplified configuration from 6 naming variations to 2 clear modes (Functions/Standalone)
    • Added XML documentation to methods
    • Added additional test cases for null projectType and trigger attribute detection

AI verification (required if AI was used):

  • I understand the code and can explain it
  • I verified referenced APIs/types exist and are correct
  • I reviewed edge cases/failure paths (timeouts, retries, cancellation, exceptions)
  • I reviewed concurrency/async behavior
  • I checked for unintended breaking or behavior changes

Testing

Automated tests

  • Result: Passed
  • All 53 generator tests passing (38 existing + 10 new configuration tests + 5 from merge)
  • Tests cover:
    • Explicit Standalone/Functions modes with overrides
    • Auto mode behavior
    • Null/default projectType behavior
    • Auto-detection via trigger attributes
    • Unrecognized value fallback

Manual validation (only if runtime/behavior changed)

  • Environment: N/A (source generator, tested via unit tests)
  • Steps + observed results:
    1. Projects with transitive Functions dependencies but no trigger attributes → Correctly generate standalone code with AddAllGeneratedTasks
    2. Projects with actual Functions trigger attributes → Correctly generate Functions-specific code
    3. Projects with explicit MSBuild property → Configuration takes precedence over auto-detection
  • Evidence: All unit tests passing, validates all code paths

Notes for reviewers

Key Changes

Intelligent Auto-Detection (Primary Solution):

  • Changed detection to check for actual usage of Azure Functions trigger attributes (OrchestrationTrigger, ActivityTrigger, EntityTrigger)
  • If methods with these attributes are found → Generate Functions-specific code
  • If no trigger attributes found → Generate standalone Durable Task Worker code (includes AddAllGeneratedTasks)
  • Assembly reference check retained as fallback for edge cases
  • This automatically solves the original problem without requiring manual configuration

Optional MSBuild Property (Manual Override):

  • DurableTaskGeneratorProjectType property available when needed
  • Values: Functions, Standalone, or Auto (default)
  • Explicit configuration takes precedence over auto-detection

Why This Approach Is Better:

  • Projects with transitive Functions dependencies but no actual Functions usage → Correctly generates standalone code
  • Precise detection based on actual usage, not just package references
  • No configuration needed in most cases

Documentation:

  • Updated src/Generators/README.md to explain the improved detection logic
  • Added XML documentation for the DetermineIsDurableFunctions method

Merge Conflict Resolution:

  • Integrated DurableEvent support from main branch while preserving project type configuration functionality

Security:

  • Uses safe, read-only Roslyn APIs
  • No external data sources or injection risks
  • All string comparisons use appropriate culture-invariant methods
Original prompt

This section details on the original issue you should resolve

<issue_title>Generator needs explicit project type configuration option</issue_title>
<issue_description>I am attempting to use the code as seen here:
https://github.com/microsoft/durabletask-dotnet/blob/main/samples/WebAPI/Program.cs

builder.Services.AddDurableTaskWorker(builder =>
{
    builder.AddTasks(r => r.AddAllGeneratedTasks());
});

However, because I have an indirect dependency (not used!) importing packages relating to Durable Functions the code generation does not generate the AddAllGeneratedTasks method. The generated code is targeting functions, when instead I am trying to use App Service.

Problem:
The code generator analyzes all imported packages and generates code targeting Azure Functions if a Functions related dependency is found. This is even true for unused transitive dependencies.

Request:
Provide an explicit option for setting the generator output project type (e.g. via Property in the csproj file)</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 3 commits December 18, 2025 11:33
- Add support for MSBuild property DurableTaskGeneratorProjectType
- Support values: DurableFunctions, Worker, DurableTaskScheduler, Auto
- Add comprehensive unit tests for all configuration scenarios
- All 46 generator tests passing

Co-authored-by: YunchuWang <[email protected]>
Copilot AI changed the title [WIP] Add explicit project type configuration option for generator Add explicit project type configuration for DurableTask source generator Dec 18, 2025
Copilot AI requested a review from YunchuWang December 18, 2025 11:44
@YunchuWang
Copy link
Member

@copilot update Worker/DurableTaskScheduler/DurableTaskWorker: Forces Worker mode
DurableFunctions/Functions/AzureFunctions: Forces Functions mode

to two modes, functions and standalone only.

…odes only

- Changed from multiple naming variations to two clear modes: "Functions" and "Standalone"
- Updated generator code to only accept "Functions" or "Standalone" (plus "Auto")
- Updated documentation to reflect simplified configuration
- Updated all tests to use new naming convention
- Reduced from 8 to 7 tests by consolidating similar scenarios

Co-authored-by: YunchuWang <[email protected]>
Copy link
Contributor Author

Copilot AI commented Dec 18, 2025

@copilot update Worker/DurableTaskScheduler/DurableTaskWorker: Forces Worker mode
DurableFunctions/Functions/AzureFunctions: Forces Functions mode

...

Updated in commit cbdc3b9. The configuration now uses two modes:

  • Functions: Forces generation of Azure Functions-specific code
  • Standalone: Forces generation of standalone Durable Task Worker code

All tests updated and passing (45 total).

@YunchuWang
Copy link
Member

@copilot resolve the conflicts

- Added DurableEventTypeInfo support from main branch
- Updated Initialize method to include durableEventAttributes provider
- Updated Execute method signature to include allEvents parameter
- Added GetDurableEventTypeInfo method
- Added DurableEventTypeInfo class
- Preserved projectType parameter functionality
- All 45 tests passing

Co-authored-by: YunchuWang <[email protected]>
Copy link
Contributor Author

Copilot AI commented Dec 30, 2025

@copilot resolve the conflicts

Conflicts resolved in commit 9786732. The branch now includes:

  • DurableEventTypeInfo support from main branch
  • Project type configuration functionality (Functions/Standalone modes)
  • All 45 tests passing

The branch is ready to merge.

@YunchuWang
Copy link
Member

YunchuWang commented Dec 30, 2025

still see the conflicts @copilot resolve the conflicts

@YunchuWang
Copy link
Member

@copilot this approach feels like a bandaid, cant we precisely detect whether project is durable function based or not? for example by checking bool isOrchestrator =
HasAttribute(parameter, "OrchestrationTriggerAttribute") &&
IsAssignableTo(parameter.Type, "TaskOrchestrationContext");
and if (attributeName is
"OrchestrationTriggerAttribute" or
"ActivityTriggerAttribute" or
"EntityTriggerAttribute")
{
return true;

…ttributes

- Changed primary detection mechanism from assembly references to actual usage of trigger attributes
- Now checks if any methods use OrchestrationTrigger, ActivityTrigger, or EntityTrigger
- Solves the original issue: projects with transitive Functions dependencies now correctly generate standalone code
- Assembly reference check kept as fallback for edge cases
- MSBuild property still available as manual override when needed
- Updated documentation to explain the improved detection logic
- All 50 tests passing

Co-authored-by: YunchuWang <[email protected]>
Copy link
Contributor Author

Copilot AI commented Dec 30, 2025

still see the conflicts @copilot resolve the conflicts

The merge conflicts have been resolved. The branch is now cleanly merged with main and includes all the latest changes including DurableEvent support.

@copilot this approach feels like a bandaid, cant we precisely detect whether project is durable function based or not? for example by checking bool isOrchestrator =
HasAttribute(parameter, "Orch...

Great suggestion! Implemented in commit 4e50616. The detection now:

  1. Primary: Checks if any methods use OrchestrationTriggerAttribute, ActivityTriggerAttribute, or EntityTriggerAttribute (via the allFunctions collection)
  2. Fallback: Checks assembly references only if no trigger attributes found
  3. Override: MSBuild property still available when manual control needed

This precisely detects actual Azure Functions usage and solves the original issue automatically - projects with transitive Functions dependencies now correctly generate standalone code without needing manual configuration.

Copilot AI changed the title Add explicit project type configuration for DurableTask source generator Improve DurableTask source generator detection and add optional project type configuration Dec 30, 2025
@YunchuWang YunchuWang marked this pull request as ready for review December 30, 2025 20:19
Copilot AI review requested due to automatic review settings December 30, 2025 20:19
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR resolves an issue where transitive dependencies on Azure Functions packages would incorrectly trigger Functions-specific code generation, preventing the use of AddAllGeneratedTasks in standalone Durable Task Worker projects. The solution implements intelligent auto-detection based on actual usage of Azure Functions trigger attributes, with an optional MSBuild configuration for manual override.

Key Changes

  • Intelligent auto-detection: The generator now checks for actual usage of Azure Functions trigger attributes (OrchestrationTrigger, ActivityTrigger, EntityTrigger) rather than solely relying on assembly references
  • Optional MSBuild configuration: Added DurableTaskGeneratorProjectType property supporting Auto (default), Functions, and Standalone values
  • Comprehensive test coverage: Added 7 new unit tests covering all configuration scenarios

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
src/Generators/DurableTaskSourceGenerator.cs Added MSBuild property reading, implemented DetermineIsDurableFunctions method for intelligent detection, updated pipeline to handle project type configuration
src/Generators/README.md Added comprehensive documentation explaining the auto-detection logic and optional MSBuild configuration with examples
test/Generators.Tests/Utils/TestHelpers.cs Added overload for RunTestAsync to support optional projectType parameter in tests
test/Generators.Tests/ProjectTypeConfigurationTests.cs New test file with 7 test methods covering explicit Standalone/Functions modes, Auto mode, and unrecognized value handling

@YunchuWang
Copy link
Member

@copilot add a test projectType = null

(可选)完全空项目 early return

- Added test for null projectType without Functions reference (generates Standalone)
- Added test for null projectType with Functions reference (detects Functions)
- These tests verify default behavior when no MSBuild property is set
- All 52 tests passing (50 original + 2 new)

Co-authored-by: YunchuWang <[email protected]>
Copy link
Contributor Author

Copilot AI commented Dec 30, 2025

@copilot add a test projectType = null

(可选)完全空项目 early return

Added in commit c22adcc. Two new tests:

  1. NullProjectType_WithoutFunctionsReference_GeneratesStandaloneCode - tests default behavior without Functions
  2. NullProjectType_WithFunctionsReference_GeneratesFunctionsCode - tests default behavior with Functions reference

All 52 tests passing.

@YunchuWang
Copy link
Member

@copilot add testcase to validate allfunction // Auto-detect based on the presence of Azure Functions trigger attributes
// If we found any methods with OrchestrationTrigger, ActivityTrigger, or EntityTrigger attributes,
// then this is a Durable Functions project
if (!allFunctions.IsDefaultOrEmpty)
{
return true;
}

- Added AutoDetect_WithTriggerAttributes_GeneratesFunctionsCode test
- Validates that presence of [ActivityTrigger] causes auto-detection as Functions project
- Tests the allFunctions.IsDefaultOrEmpty check in DetermineIsDurableFunctions
- All 53 tests passing (52 original + 1 new)

Co-authored-by: YunchuWang <[email protected]>
Copy link
Contributor Author

Copilot AI commented Dec 31, 2025

@copilot add testcase to validate allfunction // Auto-detect based on the presence of Azure Functions trigger attributes
// If we found any methods with OrchestrationTrigger, ...

Added in commit f7f328c. The new test AutoDetect_WithTriggerAttributes_GeneratesFunctionsCode validates that when code contains [ActivityTrigger] attribute (or other Functions trigger attributes), the generator auto-detects it as a Functions project via the allFunctions.IsDefaultOrEmpty check. All 53 tests passing.

@YunchuWang
Copy link
Member

@copilot update pr description to follow .github/PULL_REQUEST_TEMPLATE.md

Copy link
Contributor Author

Copilot AI commented Dec 31, 2025

@copilot update pr description to follow .github/PULL_REQUEST_TEMPLATE.md

PR description updated to follow the .github/PULL_REQUEST_TEMPLATE.md template format, including:

  • Summary section with what changed and why
  • Project checklist
  • AI-assisted code disclosure
  • Testing details
  • Notes for reviewers

@YunchuWang
Copy link
Member

case 1: standalone mode set + function dep, generate standalone
image

case 2: standalone mode not set + function dep, generate all tasks not happening
image

LGTM

// x.Left.Left.Left.Left = DurableTaskAttributes (orchestrators, activities, entities)
// x.Left.Left.Left.Right = DurableEventAttributes (events)
// x.Left.Left.Right = DurableFunctions (Azure Functions metadata)
.Select((x, _) => (x.Left.Right, x.Left.Left.Left.Left, x.Left.Left.Left.Right, x.Left.Left.Right, x.Right));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: This still makes me so sad 😅 You don't need to change it, just wanted to be sad about it :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is surely a beast.

@YunchuWang YunchuWang merged commit 58a169d into main Jan 5, 2026
8 checks passed
@YunchuWang YunchuWang deleted the copilot/add-project-type-option branch January 5, 2026 22:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Generator needs explicit project type configuration option

3 participants